`timescale 1ns / 1ps
module rhdl_pico_sdram_io(
	 input MEM_CLK_I,
    input RHDL_CLK_I,
    input RESET_I,

	 input WRITE_FIFO_I,
	 input READ_FIFO_I,
	 input [63:0] FIFO_DATA_I,
	 
    output [41:0] FIFO_DATA_O,
	 output [1:0] FIFO_STATUS_O,
	 output [12:0] TEST_BUS_O,
	 
	 //------------
	 
	 input SYS_BUSY_I,
  	 input [31:0] SYS_DATA_I,
    output [31:0] SYS_DATA_O,
    output [23:0] SYS_ADDR_O,
    output SYS_WRITE_O,
    output SYS_START_O
);


	wire memory_fifo_full;
	wire memory_fifo_empty;
	wire fpga_fifo_full;
	wire fpga_fifo_empty;
	wire [63:0] fpga_fifo_data;

	wire [12:0] test_bus;
	//wire [12:0] no_test_bus;

	reg [3:0] status_reg;

	wire fpga_read_inc;
	wire memory_write_inc;

	wire [41:0] write_data;

	wire [41:0] memory_fifo_data;

	reg [5:0] state;
    reg [5:0] next_state;

	reg [31:0] data_in;
	reg [23:0] address_in;
	reg [5:0]  route_in;
	reg write_in;	
	reg source_in;
	
	wire c_fifo_in;
	wire c_fifo_out;
	wire c_start;

   parameter S_IDLE = 6'b000001;
   parameter S_FIFO_IN = 6'b000010;
	parameter S_START = 6'b000100;
   parameter S_WAIT = 6'b001000;
   parameter S_FIFO_OUT = 6'b010000;
   parameter S_STALL = 6'b100000;

   reg [3:0] count;
   	 

fifo1 #(42,4) from_memory_fifo (
    .rdata(memory_fifo_data), 
    .wfull(memory_fifo_full), 
    .rempty(memory_fifo_empty), 
    .wdata(write_data), 
    .winc(memory_write_inc), 
    .wclk(MEM_CLK_I), 
    .wrst_n(~RESET_I), 
    .rinc(READ_FIFO_I), 
    .rclk(RHDL_CLK_I), 
    .rrst_n(~RESET_I)
	 //,.TEST_BUS_O(test_bus)
    );

fifo1 #(64,4) from_fpga_fifo (
    .rdata(fpga_fifo_data), 
    .wfull(fpga_fifo_full), 
    .rempty(fpga_fifo_empty), 
    .wdata(FIFO_DATA_I), 
    .winc(WRITE_FIFO_I), 
    .wclk(RHDL_CLK_I), 
    .wrst_n(~RESET_I), 
    .rinc(fpga_read_inc), 
    .rclk(MEM_CLK_I), 
    .rrst_n(~RESET_I)
	 //,.TEST_BUS_O(test_bus)
  );

assign test_bus = {write_in,11'b0,source_in};//{status_reg,fpga_read_inc,fpga_fifo_empty,next_state};

assign FIFO_DATA_O = memory_fifo_data;   
	
assign c_fifo_in = (next_state == S_FIFO_IN);
assign c_fifo_out = (next_state == S_FIFO_OUT);
assign c_start = (next_state == S_START);

assign fpga_read_inc = c_fifo_in;
assign memory_write_inc = c_fifo_out;
assign SYS_START_O = c_start;

assign SYS_ADDR_O = address_in;
assign SYS_DATA_O = data_in;

//assign write_data = 40'b0011111111111111111111;
assign write_data[31:0] = write_in ? data_in : SYS_DATA_I;
assign write_data[41:32] = {write_in,source_in,route_in,data_in[1:0]};
assign FIFO_STATUS_O = status_reg[1:0];
assign TEST_BUS_O = test_bus; //data_in[12:0];


assign SYS_WRITE_O = write_in;
	 
always @(negedge MEM_CLK_I or posedge RESET_I)
begin
	if (RESET_I)
	begin
		data_in <= 9;
		address_in <= 2;
		route_in <= 0;
		write_in <= 1;
		source_in <= 1;
		
		state <= S_IDLE;
		status_reg <= 0;
		
		count <= 0;
	end
	else
	begin
		state <= next_state;
		
		if (c_fifo_in)
		begin
			data_in <= fpga_fifo_data[31:0];
			address_in <= fpga_fifo_data[55:32];
			route_in <= fpga_fifo_data[61:56];
			source_in <= fpga_fifo_data[62];
			write_in <= fpga_fifo_data[63];
		end
		else
		begin
			data_in <= data_in; 
			address_in <= address_in;
			route_in <= route_in; 
			write_in <= write_in;
			source_in <= source_in;
		end
	
		if (next_state == S_FIFO_OUT)
		begin
			count <= count + 1;
		end
		else
		begin
			count <= count;
		end
		
		status_reg <= {SYS_BUSY_I,memory_fifo_full,fpga_fifo_empty,fpga_fifo_full,memory_fifo_empty};
	end
end


always @(*)
   begin
   	case (state)
   			S_IDLE : begin
				if (~fpga_fifo_empty)
					next_state <= S_FIFO_IN;
				else
					next_state <= S_IDLE;
			end
			S_FIFO_IN : begin
				if (~SYS_BUSY_I)
					next_state <= S_START;
				else
					next_state <= S_STALL;
			end
			S_STALL : begin
				if (~SYS_BUSY_I)
					next_state <= S_START;
				else
					next_state <= S_STALL;	
			end
			S_START : begin
				next_state <= S_WAIT;
			end
			S_WAIT : begin
				if (~SYS_BUSY_I & ~memory_fifo_full)
					next_state <= S_FIFO_OUT;
				else
					next_state <= S_WAIT;						
			end
			S_FIFO_OUT :begin
				if (fpga_fifo_empty)
					next_state <= S_IDLE;
				else
					next_state <= S_FIFO_IN;						
			end
		endcase
	end
endmodule


